package br.ufpe.cin.imlm2.jbeat.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class LightWeightScene implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = -2518284449141271169L;
	
	private List<ILightWeightType> types;
	private List<LightWeightClass> classes;
	private List<LightWeightMethod> entryPoints;
	private LightWeightMethod main;
	
	public LightWeightScene() {
		this.types = new ArrayList<>();
		this.classes = new ArrayList<>();
		this.entryPoints = new ArrayList<>();
	}
	
	public boolean containsType(String fullyQualifiedClassName){
		return this.getType(fullyQualifiedClassName) != null;
	}
	
	public boolean containsType(ILightWeightType type){
		return this.containsType(type.getFullyQualifiedName());
	}
	
	public void addType(ILightWeightType t){
		if(!this.containsType(t)){
			this.types.add(t);
		}
	}
	
	public boolean containsClass(String fullyQualifiedName){
		return this.getLightWeightClass(fullyQualifiedName) != null;
	}
	
	public boolean containsClass(LightWeightClass c){
		return this.containsClass(c.getFullyQualifiedName());
	}
	
	public void addClass(LightWeightClass c){
		// If the Scene doesn't know this class Type, add it!
		if(!this.containsType(c.getType())){
			this.types.add(c.getType());
		} else {
			// If it does know then we need to make sure they reference the same object
			if(c.getType() != this.getType(c.getType().getFullyQualifiedName()))
				throw new IllegalArgumentException("Class " + c.getFullyQualifiedName() + "" +
						" references a type object different from the one contained in the Scene.");
		}
		
		if(!this.containsClass(c)){
			this.classes.add(c);
		} else {
			throw new IllegalArgumentException("A class with name " + c.getFullyQualifiedName() + " " +
					"already exists in the Scene.");
		}
		
	}
	
	public ILightWeightType getType(String name){
		for (ILightWeightType type: this.types) {
			if(type.getFullyQualifiedName().equals(name))
				return type;
		}
		return null;
	}
	
	public LightWeightClass getLightWeightClass(String name){
		for (LightWeightClass c : this.classes) {
			if(c.getFullyQualifiedName().equals(name))
				return c;
		}
		return null;
	}
	
	
	public Collection<LightWeightClass> getClasses(){
		return this.classes;
	}
	
	public Collection<ILightWeightType> getTypes(){
		return this.types;
	}
	
	/**
	 * Returns a list containing all the possible entry points.
	 * Modifications in this list won't change the LightWeightScene.
	 * @return
	 */
	public List<LightWeightMethod> getEntryPoints(){
		return new ArrayList<>(this.entryPoints);
	}
	
	public void addEntryPoint(LightWeightMethod entry){
		if(!this.entryPoints.contains(entry)){
			this.entryPoints.add(entry);
		}
	}

	public LightWeightMethod getMain() {
		return main;
	}

	public void setMain(LightWeightMethod main) {
		this.main = main;
	}

}
